package cn.rocky.pandacodegen.service.impl;

import cn.rocky.pandacodegen.common.config.GeneratorConfig;
import cn.rocky.pandacodegen.common.param.GeneratorParam;
import cn.rocky.pandacodegen.common.utils.FormatUtil;
import cn.rocky.pandacodegen.common.utils.VelocityUtil;
import cn.rocky.pandacodegen.domain.entity.TemplateConfig;
import cn.rocky.pandacodegen.domain.vo.CodeFile;
import cn.rocky.pandacodegen.domain.vo.SQLContext;
import cn.rocky.pandacodegen.domain.vo.TableDefinition;
import cn.rocky.pandacodegen.service.*;
import lombok.RequiredArgsConstructor;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;


import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

@Service
@RequiredArgsConstructor
public class GeneratorServiceImpl implements GeneratorService {

    static ExecutorService executorService = Executors.newFixedThreadPool(2);

    private final TemplateConfigService templateConfigService;

//    @Autowired
//    private GenerateHistoryService generateHistoryService;

    @Value("${gen.format-xml:false}")
    private String formatXml;

    /**
     * 代码生成
     *
     * @param generatorParam  代码生成参数
     * @param generatorConfig 代码生成配置
     * @return {@code List<CodeFile>}
     */
    @Override
    public List<CodeFile> generate(GeneratorParam generatorParam, GeneratorConfig generatorConfig) {
        List<SQLContext> contextList = this.buildSQLContextList(generatorParam, generatorConfig);
        List<CodeFile>  codeFileList = new ArrayList<>();
        Velocity.init();
        for (SQLContext context : contextList) {
            if (StringUtils.hasText(generatorParam.getPackageName())) {
                context.setPackageName(generatorParam.getPackageName());
            }
            if (StringUtils.hasText(generatorParam.getDelPrefix())) {
                context.setDelPrefix(generatorParam.getDelPrefix());
            }
            if (StringUtils.hasText(generatorParam.getAuthor())) {
                context.setAuthor(generatorParam.getAuthor());
            }
            for (Integer tcId : generatorParam.getTemplateConfigIdList()) {
                TemplateConfig template = templateConfigService.getById(tcId);
                String folder = template.getFolder();
                folder = StringUtils.isEmpty(folder) ? template.getName() : doGenerator(context, folder);

                if (StringUtils.hasText(folder)) {
                    context.setPackageSubPath(folder);
                }
                // 获取文件名
                String fileName = doGenerator(context, template.getFileName());
                String content = doGenerator(context, template.getContent());
                content = this.formatCode(fileName, content);

                CodeFile codeFile = new CodeFile();
                codeFile.setFileName(fileName);
                codeFile.setFolder(folder);
                codeFile.setContent(content);
                codeFileList.add(codeFile);
            }
        }

        /**
         * executorService.execute(() -> {
         *   generateHistoryService.saveHistory(generatorParam);
         * });
         */

        return codeFileList;
    }

    /**
     * 格式代码
     *
     * @param fileName 文件名称
     * @param content  内容
     * @return {@code String}
     */
    private String formatCode(String fileName, String content) {
        if (Objects.equals("true",formatXml) && fileName.endsWith(".xml")) {
            return FormatUtil.formatXml(content);
        }
        return content;
    }

    private String doGenerator(SQLContext sqlContext, String template) {
        if (template == null) return "";
        VelocityContext context = new VelocityContext();
        Object pkColumn = sqlContext.getTableDefinition().getPkColumn();
        if (pkColumn == null) {
            pkColumn = Collections.emptyMap();
        }
        context.put("context", sqlContext);
        context.put("table"  , sqlContext.getTableDefinition());
        context.put("pk", pkColumn);
        context.put("columns", sqlContext.getTableDefinition().getColumnDefinitions());
        return VelocityUtil.generate(context, template);
    }

    /**
     * 返回 SQL 上下文列表
     *
     * @param generatorParam  代码生成参数
     * @param generatorConfig 代码生成配置
     * @return {@code List<SQLContext>}
     */
    private List<SQLContext> buildSQLContextList(GeneratorParam generatorParam, GeneratorConfig generatorConfig) {

        List<String> tableNames = generatorParam.getTableNames();

        List<SQLContext> sqlContextList = new ArrayList<>();

        SQLService service = SQLServiceFactory.build(generatorConfig);

        TableSelector tableSelector = service.getTableSelector(generatorConfig);
        tableSelector.setSchTableNames(tableNames);

        List<TableDefinition> tableDefinitions = tableSelector.getTableDefinitions();

        for (TableDefinition tableDefinition : tableDefinitions) {
            SQLContext sqlContext = new SQLContext(tableDefinition);
            sqlContext.setDbName(generatorConfig.getDbName());
            sqlContextList.add(sqlContext);
        }
        return sqlContextList;
    }
}
